package org.study.rpc.service.impl;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.study.rpc.service.Server;

/**
 * @Title: CenterImpl.java
 * @Description: TODO
 * @author zhaotf
 * @date 2018年3月18日 下午4:33:57
 * @see {@linkplain http://blog.csdn.net/rulon147/article/details/53814589}
 */
public class CenterImpl implements Server {

	private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

	private static final Map<String, Class> serviceRegistry = new HashMap<String, Class>();

	private static boolean isRunning = false;

	private static int port;

	public CenterImpl(int port) {
		this.port = port;
	}

	public void stop() {
		isRunning = false;
		executor.shutdown();
	}

	public void start() throws IOException {
		ServerSocket server = new ServerSocket();
		server.bind(new InetSocketAddress(port));
		System.out.println("start server");
		try {
			while (true) {
				// 1.监听客户端的TCP连接，接到TCP连接后将其封装成task，由线程池执行
				executor.execute(new ServiceTask(server.accept()));
			}
		} finally {
			server.close();
		}
	}

	public void register(Class serviceInterface, Class impl) {
		serviceRegistry.put(serviceInterface.getName(), impl);
	}

	public boolean isRunning() {
		return isRunning;
	}

	public int getPort() {
		return port;
	}

	private static class ServiceTask implements Runnable {
		Socket clent = null;

		public ServiceTask(Socket client) {
			this.clent = client;
		}

		public void run() {
			ObjectInputStream input = null;
			ObjectOutputStream output = null;
			try {
				// 2.将客户端发送的码流反序列化成对象，反射调用服务实现者，获取执行结果
				input = new ObjectInputStream(clent.getInputStream());
				
//				System.out.println("rpc服务端:"+input.readLine());
				
				String serviceName = input.readUTF();
				String methodName = input.readUTF();
				System.out.println("rpc服务端:"+input.readLine()+"|"+serviceName+"|"+methodName);
				Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
				Object[] arguments = (Object[]) input.readObject();
				Class<?> serviceClass = serviceRegistry.get(serviceName);
				if (serviceClass == null) {
					throw new ClassNotFoundException(serviceName + " not found");
				}
				Method method = serviceClass.getMethod(methodName, parameterTypes);
				Object result = method.invoke(serviceClass.newInstance(), arguments);

				// 3.将执行结果反序列化，通过socket发送给客户端
				output = new ObjectOutputStream(clent.getOutputStream());
				output.writeObject(result);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (output != null) {
					try {
						output.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				if (input != null) {
					try {
						input.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				if (clent != null) {
					try {
						clent.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}

		}
	}
}
